package com.qianxun.module.datasource1.develop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qianxun.module.datasource1.develop.dto.SysFunctionDTO;
import com.qianxun.module.datasource1.develop.entity.SysFunction;
import com.qianxun.module.datasource1.develop.manager.SysFunctionCacheManager;
import com.qianxun.module.datasource1.develop.mapper.SysFunctionMapper;
import com.qianxun.module.datasource1.develop.service.SysFunctionRoleRelationService;
import com.qianxun.module.datasource1.develop.service.SysFunctionService;
import com.qianxun.module.datasource1.develop.vo.SysFunctionTreeTableVo;
import com.qianxun.module.base.bo.ZTreeNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * <p>
 * 系统功能 记录系统所有的功能列表，并提供功能是否权限才能访问 服务实现类
 * </p>
 *
 * @author admin
 * @since 2019-11-13
 */
@Service
public class SysFunctionServiceImpl extends ServiceImpl<SysFunctionMapper, SysFunction> implements SysFunctionService {

    @Resource
    private SysFunctionRoleRelationService sysAdminFunctionRoleRelationService;
    @Lazy
    @Autowired
    private SysFunctionCacheManager sysFunctionCacheManager;

    @Override
    public List<ZTreeNode> searchTreeList() {
        List<SysFunction> functionList = sysFunctionCacheManager.listAll();
        return toFunctionTreeNode(functionList , ZTreeNode.class ,null);
    }

    @Override
    public List<SysFunctionTreeTableVo> searchTreeTableList() {
        List<SysFunction> functionList = sysFunctionCacheManager.listAll();
        return toFunctionTreeNode(functionList , SysFunctionTreeTableVo.class ,null);
    }

    @Override
    public void updateBatchById(Long[] ids, SysFunctionDTO query) {
        List<SysFunction> list = new ArrayList<>(ids.length);
        for(int i = 0 ;i < ids.length ;++i){
            SysFunction sysFunction = new SysFunction();
            sysFunction.setId(ids[i]);
            if(query.getStatus() != null){
                sysFunction.setStatus(query.getStatus());
            }
            if(query.getPermissionSymbol() != null){
                sysFunction.setPermissionSymbol(query.getPermissionSymbol());
            }
            list.add(sysFunction);
        }

        sysFunctionCacheManager.updateBatchByIds(list);
    }

    @Override
    public List<ZTreeNode> searchFunctionRoleTreeList(Integer functionRoleId) {
        List<SysFunction> functionList = sysFunctionCacheManager.listAll();

        List<Integer> functionIdList = sysAdminFunctionRoleRelationService.listFunctionIdByFunctionRoleId(functionRoleId);

        return toFunctionTreeNode(functionList , ZTreeNode.class ,functionIdList);
    }

    @Override
    public SysFunction getOneByFullUri(String fullUri) {
        List<SysFunction> sysFunctionList = sysFunctionCacheManager.listAll();
        for (SysFunction sysFunction : sysFunctionList) {
            String[] fullUriArray =  sysFunction.getFullUri().split(",");
            for(String s : fullUriArray){
                if(matchUri(fullUri , s)){
                    return sysFunction;
                }
            }
        }
        return null;
    }

    /**
     * 匹配uri
     * @param requestUri 请求uri
     * @param originalUri 源uri
     * @return
     */
    private boolean matchUri(String requestUri ,String originalUri){
        if(originalUri.indexOf("{") != -1){
            String[] requestUriArray = requestUri.split("/");
            String[] originalUriArray = originalUri.split("/");
            //层级不等，必不是相同uri
            if(requestUriArray.length != originalUriArray.length){
                return false;
            }
            for(int i = 0 ;i < originalUriArray.length ;++i){
                int start = originalUriArray[i].indexOf("{");
                int end = originalUriArray[i].indexOf("}");
                if(start != -1 && end != -1 && start < end){
                    continue;
                }
                if(!requestUriArray[i].equals(originalUriArray[i])){
                    return false;
                }
            }
            return true;
        }
        return requestUri.equals(originalUri);
    }
    private <T> List<T> toFunctionTreeNode(List<SysFunction> functionList , Class<? extends T> cls , List<Integer> functionIdList){
        List<T> list = new ArrayList<>(functionList.size());

        //id生成器
        AtomicLong atomicLong = maxFunctionId(functionList);

        //节点名称和id映射
        Map<String ,Long> nameIdMap = new HashMap<>(16);
        functionList.forEach(sysFunction -> {
            //创建当前功能的rootPath父节点
            createZTreeNodeAndSet(sysFunction.getRootPath() ,sysFunction.getRootPath() ,null ,null ,nameIdMap ,atomicLong ,list ,cls,sysFunction ,functionIdList);
            //创建当前功能的module父节点
            Long rootPathId = nameIdMap.get(sysFunction.getRootPath());
            String moduleNameKey = sysFunction.getRootPath() + "." + sysFunction.getModuleName();
            createZTreeNodeAndSet(moduleNameKey ,sysFunction.getModuleName() ,null ,rootPathId ,nameIdMap ,atomicLong ,list,cls,sysFunction,functionIdList);

            //创建当前功能的classDir 父节点
            Long moduleNameId = nameIdMap.get(moduleNameKey);
            String classDirKey = moduleNameKey + "." + sysFunction.getClassDir();
            createZTreeNodeAndSet(classDirKey,sysFunction.getClassDir(),null ,moduleNameId ,nameIdMap ,atomicLong ,list ,cls,sysFunction,functionIdList);

            //创建当前功能的class name 父节点
            Long classDirId = nameIdMap.get(classDirKey);
            String classNameKey = classDirKey + "." + sysFunction.getClassName();
            createZTreeNodeAndSet(classNameKey ,sysFunction.getClassName(),null ,classDirId ,nameIdMap ,atomicLong ,list ,cls,sysFunction,functionIdList);
            //创建当前功能节点
            Long classNameId = nameIdMap.get(classNameKey);
            createZTreeNodeAndSet(sysFunction.getFullUri() ,sysFunction.getFullUri(),sysFunction.getId() ,classNameId ,nameIdMap ,atomicLong ,list ,cls ,sysFunction,functionIdList);
        });

        if(cls.isAssignableFrom(ZTreeNode.class)) {
            list.add((T) ZTreeNode.createParent());
        }
        return list;
    }

    private <T> void createZTreeNodeAndSet(String key , String name , Long id , Long pid , Map<String ,Long> nameIdMap , AtomicLong idGenerator , List<T> list , Class<? extends T> cls , SysFunction sysFunction , List<Integer> functionIdList){
        if(!StringUtils.isEmpty(name)){
            if(nameIdMap.get(key) == null){
                long nowId = id == null ? idGenerator.incrementAndGet() : id;
                long nowPid = pid == null ? 0L : pid;
                boolean open = nowPid == 0 ? true : false;
                nameIdMap.put(key ,nowId);

                if(cls.isAssignableFrom(ZTreeNode.class)) {
                    ZTreeNode zTreeNode = buildZTreeNode(nowId, nowPid, name, open);
                    //设置选中
                    if(functionIdList != null && functionIdList.contains((int)nowId)){
                        zTreeNode.setChecked(true);
                    }
                    list.add((T)zTreeNode);
                }else if(cls.isAssignableFrom(SysFunctionTreeTableVo.class)){
                    SysFunctionTreeTableVo sysFunctionTreeTableVo = new SysFunctionTreeTableVo();
                    sysFunctionTreeTableVo.setId(nowId).setName(name).setPid(nowPid);
                    if(sysFunction.getClassName().equals(name)){
                        sysFunctionTreeTableVo.setUri(sysFunction.getClassUri()).setUriMethod(sysFunction.getClassUriMethod());
                    }else if(sysFunction.getFullUri().equals(name)){
                        sysFunctionTreeTableVo.setName(sysFunction.getFnName()).setArgs(sysFunction.getFnArgs())
                                .setUri(sysFunction.getFnUri()).setUriMethod(sysFunction.getFnUriMethod()).setFullUri(sysFunction.getFullUri())
                                .setPermissionSymbol(sysFunction.getPermissionSymbol()).setStatus(sysFunction.getStatus()).setResultType(sysFunction.getResultType());
                    }
                    list.add((T)sysFunctionTreeTableVo);
                }
            }
        }
    }

    private ZTreeNode buildZTreeNode(long id , long pid , String name , boolean open){
        return new ZTreeNode().setId(id).setPId(pid).setName(name).setOpen(open);
    }

    /**
     * 当前最大id
     * @param functionList
     * @return
     */
    private AtomicLong maxFunctionId(List<SysFunction> functionList){
        AtomicLong atomicLong = new AtomicLong(0);
        for (SysFunction sysFunction : functionList) {
            if(sysFunction.getId() > atomicLong.get()){
                atomicLong.set(sysFunction.getId());
            }
        }
        return atomicLong;
    }
}
